Functional programming with the FC++ library

نویسندگان

  • Brian McNamara
  • Yannis Smaragdakis
چکیده

We describe the FC++ library, a rich library supporting functional programming in C++. Prior approaches to encoding higher order functions in C++ have su ered with respect to polymorphic functions from either lack of expressiveness or high complexity. In contrast, FC++ o ers full and concise support for higher-order polymorphic functions through a novel use of C++ type inference. The FC++ library has a number of useful features, including a generalized mechanism to implement currying in C++, a \lazy list" class which enables the creation of \in nite data structures", a subtype polymorphism facility, and an extensive library of useful functions, including a large part of the Haskell Standard Prelude. The FC++ library has an eÆcient implementation. We show the results of a number of experiments which demonstrate the value of optimizations we have implemented. These optimizations have improved the run-time performance by about an order of magnitude for some benchmark programs that make heavy use of FC++ lazy lists. We also make an informal performance comparison with similar programs written in Haskell. 1 Motivation and Overview It is a little known fact that part of the C++ Standard Library consists of code written in a functional style. Although the C++ Standard Library o ers rudimentary support for higher order functions and currying, it stops short of supplying a sophisticated and reusable module for general purpose functional programming. This is the gap that our work aims to ll. The result is a full embedding of a simple pure functional language in C++, using the extensibility capabilities of the language and the existing compiler and run-time infrastructure. At rst glance it may seem that C++ is antithetical to the functional paradigm. The language not only supports direct memory manipulation but also only has primitive capabilities for handling functions. Function pointers are rst-class entities, but they are of little use since new functions cannot be created on the y (e.g. as specializations of existing functions by xing some state information). Nevertheless, the elements required to implement a functional programming framework are already in the language. The technique of representing rst-class functions using classes is well known in the object-oriented world. Among others, the Pizza language (Odersky and Wadler, 1997) uses this approach in translating functionallyavored constructs to Java code. The same technique is used in previous implementations of higher-order functions in C++ (Kiselyov, 1998; L aufer, 1995). C++ also allows 2 Brian McNamara and Yannis Smaragdakis users to de ne a familiar syntax for function-classes, by overloading the function application operator, \()". Additionally one can declare methods so that they are prevented from modifying their arguments; this property is enforced statically by C++ compilers. Finally, using the C++ inheritance capabilities and dynamic dispatch mechanism, one can de ne variables that range over all functions with the same type signature. In this way, a C++ user can \hijack" the underlying language mechanisms to provide a functional programming model. All of the above techniques are well-known and have been used before. In fact, several researchers in the recent past (Striegnitz, 2001; Kiselyov, 1998; J arvi and Powell, 2002; Laufer, 1995; Meijer and Kettner, 2000) have (re)discovered that C++ can be used for functional programming. Nevertheless, all of the above approaches, as well as that of the C++ Standard Library, su er from one of two drawbacks: High complexity when polymorphic functions are used : Polymorphic functions may need to be explicitly turned into monomorphic instances before they can be used. This causes the implementation to become very complex. L aufer observed in (1995): \...the type information required in more complex applications of the framework is likely to get out of hand, especially when higher numbers of arguments are involved." Lack of expressiveness : In order to represent polymorphic functions, one can use C++ function templates. This approach does not su er from high complexity of parameterization, because the type parameters do not need to be speci ed explicitly whenever a polymorphic function is used. Unfortunately, function templates cannot be passed as arguments to other function templates. Thus, using C++ function templates, polymorphic functions cannot take other polymorphic functions as arguments. This is evident in the C++ Standard Library, where \higher order" polymorphic operators like compose1, bind1st, etc. are not \functions" inside the Standard Library framework and, hence, cannot be passed as arguments to themselves or other operators. Our work addresses both of the above problems. Contrary to prior belief (see Laufer (1995), who also quotes personal communication with Dami) no modi cation to the language or the compiler is needed. Instead, we are relying on an innovative use of C++ type inference. E ectively, our framework maintains its own type system, in which polymorphic functions can be speci ed and other polymorphic functions can recognize them as such. [Important note: Since C++ type inference is in the core of our technique, a disclaimer is in order: C++ type inference is a uni cation process matching the types of actual arguments of a function template to the declared polymorphic types (which may contain type variables, whose value is determined by the inference process). C++ type inference does not solve a system of type equations and does not relieve the programmer from the obligation to specify type signatures for functions. Thus, the term \C++ type inference" should not be confused with \type inference" as employed in functional languages like ML or Haskell. The overloading is unfortunate but unavoidable as use of both terms is widespread. We will always use the pre x \C++" when we refer to \C++ type inference".] Functional Programming with the FC++ Library 3 The result of our approach is a convenient and powerful parametric polymorphism scheme that is well integrated in the language: with the FC++ library, C++ o ers as much support for higher-order polymorphic functions as it does for native types (e.g. integers and pointers). Apart from the above novelty, FC++ also o ers a few more new elements: First, we de ne a subtyping policy for functions of FC++, thus supporting subtype polymorphism. The default policy is what one would expect: a function A is a subtype of function B, i A and B have the same number of arguments, all arguments of B are subtypes of the corresponding arguments of A, and the return value of A is a subtype of the return value of B. (Using OO typing terminology, we say that our policy is covariant with respect to return types and contravariant with respect to argument types.) Subtype substitutability is guaranteed; a function Animal* -> Dog* can be used where a function Mammal* -> Mammal* is expected. Second, FC++ provides reusable combinators to support automatic currying. Curryable functions can be called with a subset of the arguments they expect, and those values will be bound, resulting in a new function that expects the remainder of the arguments. Third, FC++ has a high level of technical maturity. For instance, compared to Laufer's approach, we achieve an equally safe but more eÆcient implementation of the basic framework for higher order functions. In a previous paper (McNamara and Smaragdakis, 2000a), we illustrated that our implementation was 4 to 8 times faster than Laufer's. In this paper, we describe a number of new optimizations we have recently applied to the library, and demonstrate that the performance has increased by almost an order of magnitude compared to our old implementation. Additionally, FC++ builds signi cant functionality on top of the basic framework. We export two fairly mature reference-counting \pointer" classes to library users, so that use of C++ pointers can be completely eliminated at the user level. We de ne a wealth of useful functions (a large part of the Haskell Standard Prelude) to enhance the usability of FC++ and demonstrate the expressiveness of our framework. It should be noted that de ning these functions in a convenient, reusable form is possible exactly because of the support for polymorphic functions o ered by FC++. It is no accident that such higher-order library functions are missing from other C++ libraries: supplying explicit types would be tedious and would render the functions virtually unusable. The rest of the paper is organized as follows: Section 2 gives a brief introduction to the library with some short code examples. Section 3 describes direct functoids. (We use the term \functoid" to describe our implementation of functions; the term is borrowed from Laufer (1995).) Direct functoids enable the creation of higherorder polymorphic functions, and are one of the key innovations of FC++. Section 4 describes indirect functoids. Indirect functoids are monomorphic, but they are rst-class and support subtype polymorphism. Section 5 demonstrates how direct functoids simplify the task of programming with polymorphic functions in 4 Brian McNamara and Yannis Smaragdakis FC++. Section 6 describes two other features of FC++. Section 6.1 describes how currying is implemented in FC++. Reusable combinators can be wrapped around any functoid to make it curryable, and we introduce a nice syntax for binding a subset of a functions' arguments. Section 6.2 describes how subtype polymorphism is implemented for indirect functoids. Section 7 describes how FC++ interfaces with its host language. Section 8 describes the expressiveness of the library, as well as the fundamental limitations imposed by C++. Section 9 discusses the run-time performance of the library. Section 10 analyzes the performance and discusses a number of optimizations we have applied to the implementation. Section 11 describes some details of the lazy list implementation in FC++. Section 12 gives a summarizing overview of the library and a description of the organization of its modules. Section 13 describes a few applications of the library. Section 14 discusses related work. 2 Library Introduction In this section we give a brief overview of how the FC++ library is used. Figure 1 will serve as a running example to illustrate the main features of the library. FC++ lists support the usual list interface; cons(), null(), head(), and tail() are among the basic functions that work on Lists. Lists are parameterized by the data type they contain; Lists and the associated functions are polymorphic. Part (A) of Figure 1 illustrates some basic list code. FC++ has a number of higher-order functions, like compose(), which can take polymorphic functions as arguments. Part (B) of Figure 1 illustrates that compose(tail,tail) yields a new (polymorphic) function which discards the rst two elements of a list. FC++ is the only C++ library that enables the user to generally combine higherorder functions with polymorphic ones; with FC++, polymorphic functions may be passed as arguments to other functions and returned as results. FC++ Lists are lazy. Part (C) of Figure 1 demonstrates in nite lists in FC++; the elements of the list are produced only as they are needed. FC++ functoids support currying. For example, in Part (D) of Figure 1, plus() is a two-argument function, but it can be called with just one argument, yielding a new one-argument function as a result. In the example, map() applies this new function to each element of the list, yielding a new lists where all of the values have been incremented by 1. As seen in the example, map() is also curryable. To bind values to arguments other than the initial arguments, an underscore can be used as a placeholder for arguments that should be curried. The FC++ library contains more than 50 useful functions from the Haskell Standard Prelude (Peyton-Jones and Hughes, 1999). The prior examples have already used familiar functions like map() and filter(); FC++ o ers dozens of such general functions, including take(), which selects the rst N elements of a list, and foldl1() which left-accumulates all of the values in a list using a given function. Part (E) of Figure 1 demonstrates such functionality. FC++ has \indirect functoids", run-time variables which can be bound to any function with a given monomorphic signature. Part (F) of Figure 1 illustrates an Functional Programming with the FC++ Library 5 int x=1, y=2, z=3; string s="foo", t="bar"; // (A) List basics List li = cons( x, cons( y, cons( z, NIL ))); List ls = cons( s, cons( t, NIL )); assert( head(ls) == "foo" ); assert( length(tail(li)) == 1 ); // (B) Higher-order polymorphic compose() li = compose( tail, tail )(li); assert( head(li) == 3 ); // (C) Laziness (infinite lists) li = enumFrom(1); // [1,2,3,...] li = filter(even,li); // [2,4,6,...] // (D) Currying li = map( plus(1), li ); li = map( plus(1) )( li ); li = map( _, li )( plus(1) ); // (E) Haskell Standard Prelude li = take( 5, enumFrom(1) ); assert( foldr(plus,3,li) == 18 ); assert( foldl1(plus,ls) == "foobar" ); // (F) Indirect functoids Fun2 f = monomorphize1( plus ); assert( f(3,2) == 5 ); f = minus; // implicit conversion assert( f(3,2) == 1 ); Fig. 1. Some examples of what FC++ can do indirect functoid variable f of type Fun2|a two-argument function which takes two integer arguments and returns an integer result. This variable can be bound to di erent functions with the right signature, for instance, plus() or minus(). Since plus() is a polymorphic function, a monomorphic instance must be selected to be bound to the indirect functoid variable. This monomorphizing conversion may be done either explicitly or implicitly.

برای دانلود متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

منابع مشابه

FC++: Functional tools for object-oriented tasks

FC++ is a library for programming functionally in C++. Compared to other C++ functional programming libraries, FC++ is distinguished by its powerful type system which allows manipulating parametrically polymorphic functions (e.g., passing them as arguments to other functions and returning them as results). In this paper, we show how FC++ can be used in common OO programming tasks. We demonstrat...

متن کامل

Efficiency of Bulk Synchronous Parallel Programming using C++, BSFC++ and BSMLlib

The BSMLlib library is a library for Bulk Synchronous Parallel (BSP) programming with the functional language Objective Caml. It is based on an extension of the λ-calculus by parallel operations on a parallel data structure named parallel vector, which is given by intention. The BSFC++ library is a library for Functional Bulk Synchronous Parallel programming in C++ which is based on the FC++ li...

متن کامل

The Relationship of Child Abuse and Functional Constipation in Children: A Case-Control Study

Background: Child abuse is a serious global problem and can be in the form of physical, sexual, emotional or neglect by not providing for the child's needs. Functional constipation (FC) is a common functional gastrointestinal (GI) disorder in children. This study was aimed to assess the relationship between child abuse and fu...

متن کامل

Distinguishing Functional Constipation from Organic Causes in Children

  The diagnosis of functional constipation (FC) is usually straightforward. Almost 95% of childhood constipation is functional in nature. The remaining 5% can be attributed to wide variety of conditions. Many of these etiologies are obvious by history and examination and many have other specific symptoms besides constipation. It is especially important to look for presence of any symptoms or si...

متن کامل

برآورد برخی از نقاط منحنی مشخصه رطوبتی خاک شامل FC و PWP با استفاده از توابع انتقالی خاک و روش رگرسیونی در بردسیر کرمان

Field capacity and permasent wilting point are the most important parameters in designing and programming irrigation, whose measurements are troublesome and time-consuming. But these parameters could be estimated by easy data characteristics such as soil texture, organic matter and gypsum, using Pedotransfer Functions (PTFs) with high precision. In order to estimate soil moisture at FC and PWP ...

متن کامل

ذخیره در منابع من


  با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید

برای دانلود متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

عنوان ژورنال:
  • J. Funct. Program.

دوره 14  شماره 

صفحات  -

تاریخ انتشار 2004